﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Diagnostics;

namespace DeepHash.Document.Format
{
    /// <summary>
    /// Text formatter for the Verification Document
    /// </summary>
    public class TextDocumentFormatter : IDocumentFormatter
    {
        #region IDocumentFormatter Members

        private string _basePath = string.Empty;
        /// <summary>
        /// The base path of the file paths. If relative path is used then this 
        /// should be empty. But if full path like c:\dir1\dir2\file1 is used then
        /// this should be set to the base path
        /// </summary>
        public string BasePath
        {
            get { return _basePath; }
            set { _basePath = value; }
        }

        public bool SaveDocument(System.IO.Stream stream, VerificationDocument doc)
        {
            if (stream.CanWrite)
            {
                // Create a writer to write to stream
                StreamWriter writer = new StreamWriter(stream);
                WriteFolderRecord(writer, doc, this.BasePath);
                // Make sure we flush before we close. Otherwise we would end up with
                // items not written in the file
                writer.Flush();
                return true;
            }
            return false;
        }

        private string _outputFormat = "{0} {1}";
        protected string OutputFormat
        {
            get { return _outputFormat; }
            set { _outputFormat = value; }
        }

        private void WriteFolderRecord(StreamWriter writer, FolderVerificationRecord folderRec, string folderPath)
        {
            foreach (FileVerificationRecord fileRec in folderRec.Files)
            {
                writer.WriteLine (OutputFormat, fileRec.HashString, string.Format("{0}\\{1}", folderPath, fileRec.Name));
            }

            foreach (FolderVerificationRecord childFolderRec in folderRec.Folders)
            {
                WriteFolderRecord(writer, childFolderRec, string.Format("{0}\\{1}", folderPath, childFolderRec.Name));
            }
        }

        public VerificationDocument LoadDocument(System.IO.Stream stream)
        {
            StreamReader reader = new StreamReader(stream);
            VerificationDocument doc = new VerificationDocument();
            string lineToProcess = string.Empty;

            Dictionary<string, VerificationRecord> dic = new Dictionary<string, VerificationRecord>();
            while (!reader.EndOfStream)
            {
                lineToProcess = reader.ReadLine();
                ProcessLine(doc, lineToProcess, dic);
            }
            return doc;
        }


        private void ProcessLine(VerificationDocument doc, string lineToProcess, Dictionary<string, VerificationRecord> dic)
        {
            int indexOfFirstSpace = lineToProcess.IndexOf(" ");
            if (indexOfFirstSpace > -1)
            {
                string hashString = lineToProcess.Substring(0, indexOfFirstSpace);
                string filepath = lineToProcess.Substring(indexOfFirstSpace, lineToProcess.Length - indexOfFirstSpace).Trim();
                if (!string.IsNullOrEmpty(BasePath))
                {
                    if (filepath.ToLower().StartsWith(BasePath.ToLower()))
                    {
                        filepath = filepath.Substring(BasePath.Length);
                    }
                    else
                    {
                    }
                }
                else
                { 
                }

                int indexOfLastPart = filepath.LastIndexOf("\\");
                if (indexOfLastPart > -1)
                {
                    string folderPath = filepath.Substring(0, indexOfLastPart );
                    EnsureFolderPath(doc, string.Empty, folderPath, dic);
                    string folderPathWithoutSlash = RemoveStartingSlash(folderPath);
                    FolderVerificationRecord folder = (FolderVerificationRecord) dic[folderPathWithoutSlash];
                    FileVerificationRecord fileRec = new FileVerificationRecord();
                    fileRec.HashString = hashString;
                    fileRec.Name = RemoveStartingSlash(GetFilenameFromPath(filepath));
                    folder.Files.Add(fileRec);
                }
            }
        }

        private void EnsureFolderPath(FolderVerificationRecord parent, string parentPath, string path, Dictionary<string, VerificationRecord> dic)
        {
            string folder = GetFirstFolderNameFromPath(ref path);
            folder = RemoveStartingSlash(folder);
            string key = RemoveStartingSlash( JoinPath(parentPath , folder));
            if (!dic.ContainsKey(key))
            {
                FolderVerificationRecord rec = new FolderVerificationRecord();
                rec.Name = folder;
                dic.Add(key, rec);
                parent.Folders.Add(rec);
            }
            FolderVerificationRecord parentOfChild = (FolderVerificationRecord)dic[key];
            if (!string.IsNullOrEmpty(path))
            {
                EnsureFolderPath(parentOfChild, key, path, dic);
            }
        }

        private string JoinPath(string parent, string child)
        {
            if (string.IsNullOrEmpty(parent) && string.IsNullOrEmpty(child))
            {
                return string.Empty;
            }
            if (parent.EndsWith("\\") || child.StartsWith("\\"))
            {
                return string.Format("{0}{1}", parent, child);
            }
            else
            {
                return string.Format("{0}\\{1}", parent, child);
            }
        }

        private string RemoveStartingSlash(string path)
        {
            if (path.StartsWith ("\\"))
                return path.Substring ( 1, path.Length -1);
            else
                return path;
        }


        private string GetFolderPathNameFromPath(string path)
        {
            string result = path;
            int indexOfLast = path.LastIndexOf("\\");
            if (indexOfLast > -1)
            {
                result = path.Substring(0, indexOfLast);
            }
            return result;
        }

        private string GetFilenameFromPath(string path)
        {
            string result = path;
            int indexOfLast = path.LastIndexOf("\\");
            if (indexOfLast > -1)
            {
                result = path.Substring(indexOfLast , path.Length - indexOfLast );
            }
            return result;
        }

        private string GetFirstFolderNameFromPath(ref string path)
        {
            string ret = string.Empty;
            if (string.IsNullOrEmpty(path))
            {
                return string.Empty;
            }
            int indexOfFirstPart = path.IndexOf("\\",1);
            if (indexOfFirstPart > -1)
            {
                ret = path.Substring(0, indexOfFirstPart);
                path = path.Substring(indexOfFirstPart, path.Length - indexOfFirstPart);
            }
            else
            {
                if (path.StartsWith("\\"))
                {
                    ret = path.Substring(1, path.Length - 1);
                    path = string.Empty;
                }
            }
            return ret;
        }

        #endregion
    }
}
